package cn.yudao.ymcc.service.impl;

import cn.yudao.ymcc.config.RedisConfig;
import cn.yudao.ymcc.domain.KillActivity;
import cn.yudao.ymcc.domain.KillCourse;
import cn.yudao.ymcc.mapper.KillActivityMapper;
import cn.yudao.ymcc.service.IKillActivityService;
import cn.yudao.ymcc.service.IKillCourseService;
import cn.yudao.ymcc.utils.AssertUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.swagger.annotations.Authorization;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale.jia
 * @since 2022-08-23
 */
@Service
public class KillActivityServiceImpl extends ServiceImpl<KillActivityMapper, KillActivity> implements IKillActivityService {

    @Autowired
    private IKillCourseService killCourseService;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
    * @Title: publish
    * @Description: 发布秒杀活动
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/23 18:13
    * @Parameters:
    * @Return
    */
    @Override
    @Transactional
    public void publish(Long activityId) {
        // 校验非空 - jsr303
        // 获取秒杀活动对象
        KillActivity killActivity = selectById(activityId);
        // 判断活动是否不为空
        AssertUtil.isNotNull(killActivity,"活动不存在");
        // 判断活动状态是否为未发布
        AssertUtil.isTrue(killActivity.getPublishStatus() == KillActivity.WAIT_PUBLICATION,"活动已发布或取消");
        // 判断活动时间是否过期
        AssertUtil.isTrue(new Date().before(killActivity.getEndTime()),"活动时间已结束");
        // 获取参与当前秒杀活动的商品信息
        List<KillCourse> killCourses =  selectKillCourseByActivityId(activityId);
        // 将秒杀商品放到redis中并为了避免高并发的情况我们使用redis的信号量--redisson
        Date now = new Date(); // 获取当前时间
        List<KillCourse> killCourseList = killCourses.stream().map(killCourse -> {
            // 我们需要给当前商品设置信号量--秒杀库存数--先获取信号量
            String SemaphoreKey = activityId + ":" + killCourse.getId();
            RSemaphore semaphore = redissonClient.getSemaphore(SemaphoreKey);
            // 给信号量赋值
            boolean isSuccess = semaphore.trySetPermits(killCourse.getKillCount());
            if (isSuccess) {
                // 因为存储秒杀商品的时候 我们是一个活动对应多个秒杀商品，
                // 且为了能快速得到秒杀活动中某个商品的值 我们使用redis的hash来存储数据
                // key(活动id)-key（秒杀商品id）-value（秒杀商品）
                redisTemplate.opsForHash().put("activity:" + activityId, "killCourse:" + killCourse.getId(), killCourse);
                killCourse.setPublishTime(now); // 发布到redis的时间
                killCourse.setPublishStatus(KillCourse.SUCCESS_PUBLICATION); // 设置状态
            } else {
                // 保存日志 -- 通知客服或者管理员处理
            }
            return killCourse;
        }).collect(Collectors.toList());
        // 修改活动信息
        killActivity.setPublishStatus(KillActivity.SUCCESS_PUBLICATION); // 状态
        killActivity.setPublishTime(new Date()); // 发布时间
        // 修改活动信息
        updateById(killActivity);
        // 修改商品信息
        killCourseService.updateBatchById(killCourseList);


    }

    /**
    * @Title: insertRelease
    * @Description: 新增-配置redis的监听key事件来完成自动发布
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/24 21:16
    * @Parameters:
    * @Return
    */
    @Override
    public void insertRelease(KillActivity killActivity) {
        insert(killActivity);
        // 获取活动的发布时间
        long beginTime = killActivity.getBeginTime().getTime();
        // 获得当前时间
        long now = System.currentTimeMillis();
        // 得到时间差并减少一天
        long time = (long)(beginTime-now-1*24*60*60*1000)/1000;
        // 存入redis中设置过期时间未time
        redisTemplate.opsForValue().set("activityKey:" + killActivity.getId(),"1",time, TimeUnit.SECONDS);
    }

    public List<KillCourse> selectKillCourseByActivityId(Long activityId) {

        Wrapper<KillCourse> wrapper = new EntityWrapper<>();
        wrapper.eq("activity_id",activityId);
        return killCourseService.selectList(wrapper);
    }
}
